﻿using System;
using System.Collections.Generic;

namespace Kooboo.CMS.MediaSyncWrapper
{
    using System.IO;
    using Kooboo.CMS.Content.Models;
    using Kooboo.CMS.Content.Services;
    using Kooboo.CMS.Sites.Models;
    using Kooboo.CMS.Sites.Persistence;

    public class MediaContentManagerWrapper : MediaContentManager
    {
        public MediaContentManagerWrapper()
        {
            this.SiteProvider = Kooboo.CMS.Sites.Persistence.Providers.SiteProvider;
        }

        ISiteProvider SiteProvider
        {
            get;
            set;
        }

        #region Add

        private MediaContent BaseAdd(Repository repository, MediaFolder binaryFolder, string fileName, Stream fileStream, bool overrided, string userId = "")
        {
            try
            {
                fileStream.Position = 0;
                return base.Add(repository, binaryFolder, fileName, fileStream, overrided, userId);
            }
            catch(Exception e)
            {
                Kooboo.HealthMonitoring.Log.LogException(e);
            }

            return null;
        }

        public override MediaContent Add(Repository repository, MediaFolder binaryFolder, string fileName, Stream fileStream, bool overrided, string userId = "")
        {
            var mediaContent = this.BaseAdd(repository, binaryFolder, fileName, fileStream, overrided, userId);

            this.SyncToSubSites(
                Site.Current,
                binaryFolder,
                fileName,
                fileStream,
                overrided,
                userId,
                (Repository, BinaryFolder, FileName, FileStream, Overrided, UserId) =>
                {
                    this.BaseAdd(Repository, BinaryFolder, FileName, FileStream, Overrided, UserId);
                }
            );

            return mediaContent;
        }

        private void SyncToSubSites(Site site, MediaFolder binaryFolder, string fileName, Stream fileStream, bool overrided, string userId, Action<Repository, MediaFolder, string, Stream, bool, string> syncAction)
        {
            foreach(var subSite in this.SiteProvider.ChildSites(site))
            {
                if(syncAction != null)
                {
                    syncAction(subSite.GetRepository(), binaryFolder, fileName, fileStream, overrided, userId);
                }

                this.SyncToSubSites(subSite, binaryFolder, fileName, fileStream, overrided, userId, syncAction);
            }
        }

        #endregion

        #region Update

        #region Update(MediaFolder, string, IEnumerable<string>, IEnumerable<object>)

        private void BaseUpdate(MediaFolder folder, string uuid, IEnumerable<string> fieldNames, IEnumerable<object> fieldValues)
        {
            try
            {
                base.Update(folder, uuid, fieldNames, fieldValues);
            }
            catch(Exception e)
            {
                Kooboo.HealthMonitoring.Log.LogException(e);
            }
        }

        public override void Update(MediaFolder folder, string uuid, IEnumerable<string> fieldNames, IEnumerable<object> fieldValues)
        {
            this.BaseUpdate(folder, uuid, fieldNames, fieldValues);

            this.SyncToSubSites(
                Site.Current,
                folder,
                uuid,
                fieldNames,
                fieldValues,
                (MediaFolder, UUID, FieldNames, FieldValues) =>
                {
                    this.BaseUpdate(MediaFolder, UUID, FieldNames, FieldValues);
                }
            );
        }

        private void SyncToSubSites(Site site, MediaFolder folder, string uuid, IEnumerable<string> fieldNames, IEnumerable<object> fieldValues, Action<MediaFolder, string, IEnumerable<string>, IEnumerable<object>> syncAction)
        {
            foreach(var subSite in this.SiteProvider.ChildSites(site))
            {
                if(syncAction != null)
                {
                    syncAction(folder, uuid, fieldNames, fieldValues);
                }

                this.SyncToSubSites(subSite, folder, uuid, fieldNames, fieldValues, syncAction);
            }
        }

        #endregion

        #region Update(Repository, MediaFolder, string, string, Stream, string)

        private MediaContent BaseUpdate(Repository repository, MediaFolder binaryFolder, string uuid, string fileName, Stream fileStream, string userid = "")
        {
            try
            {
                return base.Update(repository, binaryFolder, uuid, fileName, fileStream, userid);
            }
            catch(Exception e)
            {
                Kooboo.HealthMonitoring.Log.LogException(e);
            }

            return null;
        }

        public override MediaContent Update(Repository repository, MediaFolder binaryFolder, string uuid, string fileName, Stream fileStream, string userid = "")
        {
            var mediaContent = this.BaseUpdate(repository, binaryFolder, uuid, fileName, fileStream, userid);

            this.SyncToSubSites(
                Site.Current,
                binaryFolder,
                uuid,
                fileName,
                fileStream,
                userid,
                (Repository, MediaFolder, UUID, FileName, FileStream, UserId) =>
                {
                    this.BaseUpdate(Repository, MediaFolder, UUID, FileName, FileStream, UserId);
                }
            );

            return mediaContent;
        }

        private void SyncToSubSites(Site site, MediaFolder binaryFolder, string uuid, string fileName, Stream fileStream, string userid, Action<Repository, MediaFolder, string, string, Stream, string> syncAction)
        {
            foreach(var subSite in this.SiteProvider.ChildSites(site))
            {
                if(syncAction != null)
                {
                    syncAction(subSite.GetRepository(), binaryFolder, uuid, fileName, fileStream, userid);
                }

                this.SyncToSubSites(subSite, binaryFolder, uuid, fileName, fileStream, userid, syncAction);
            }
        }

        #endregion

        #endregion

        #region Delete

        private void BaseDelete(Repository repository, Folder folder, string uuid)
        {
            try
            {
                base.Delete(repository, folder, uuid);
            }
            catch(Exception e)
            {
                Kooboo.HealthMonitoring.Log.LogException(e);
            }
        }

        public override void Delete(Repository repository, Folder folder, string uuid)
        {
            this.BaseDelete(repository, folder, uuid);

            this.SyncToSubSites(
                Site.Current,
                folder,
                uuid,
                (Repository, Folder, UUID) =>
                {
                    this.BaseDelete(Repository, Folder, UUID);
                }
            );
        }

        private void SyncToSubSites(Site site, Folder folder, string uuid, Action<Repository, Folder, string> syncAction)
        {
            foreach(var subSite in this.SiteProvider.ChildSites(site))
            {
                if(syncAction != null)
                {
                    var repository = subSite.GetRepository();
                    syncAction(repository, new MediaFolder(repository, folder.FullName), uuid);
                }

                this.SyncToSubSites(subSite, folder, uuid, syncAction);
            }
        }

        #endregion

        #region Move

        private void BaseMove(Repository repository, string sourceFolder, string oldFileName, string targetFolder, string newFileName)
        {
            try
            {
                base.Move(repository, sourceFolder, oldFileName, targetFolder, newFileName);
            }
            catch(Exception e)
            {
                Kooboo.HealthMonitoring.Log.LogException(e);
            }
        }

        public override void Move(Repository repository, string sourceFolder, string oldFileName, string targetFolder, string newFileName)
        {
            this.BaseMove(repository, sourceFolder, oldFileName, targetFolder, newFileName);

            this.SyncToSubSites(
                Site.Current,
                sourceFolder,
                oldFileName,
                targetFolder,
                newFileName,
                (Repository, SourceFolder, OldFileName, TargetFolder, NewFileName) =>
                {
                    this.BaseMove(Repository, SourceFolder, OldFileName, TargetFolder, NewFileName);
                }
            );
        }

        private void SyncToSubSites(Site site, string sourceFolder, string oldFileName, string targetFolder, string newFileName, Action<Repository, string, string, string, string> syncAction)
        {
            foreach(var subSite in this.SiteProvider.ChildSites(site))
            {
                if(syncAction != null)
                {
                    syncAction(subSite.GetRepository(), sourceFolder, oldFileName, targetFolder, newFileName);
                }

                this.SyncToSubSites(subSite, sourceFolder, oldFileName, targetFolder, newFileName, syncAction);
            }
        }

        #endregion
    }
}